#include <func.h>

typedef struct {
	int id;
	int balance;
	pthread_mutex_t mutex; // 细粒度锁
} Account;

Account acct1 = {1, 100, PTHREAD_MUTEX_INITIALIZER};
Account acct2 = {2, 1000, PTHREAD_MUTEX_INITIALIZER};

pthread_mutex_t protection = PTHREAD_MUTEX_INITIALIZER;

int transfer(Account* acctA, Account* acctB, int money) {
	/* if (acctA->id < acctB->id) { */
	/* 	pthread_mutex_lock(&acctA->mutex); */
	/* 	sleep(1); */
	/* 	pthread_mutex_lock(&acctB->mutex); */
	/* } else { */
	/* 	pthread_mutex_lock(&acctB->mutex); */
	/* 	sleep(1); */
	/* 	pthread_mutex_lock(&acctA->mutex); */
	// }

	/* start: */
	/* 	pthread_mutex_lock(&acctA->mutex); */ 
	/* 	sleep(1); */
	/* 	int err = pthread_mutex_trylock(&acctB->mutex); */
	/* 	if (err == EBUSY) { */
	/* 		pthread_mutex_unlock(&acctA->mutex); */
	/* 		int nsecs = rand() % 5; */
	/* 		sleep(nsecs); */
	/* 		goto start; */
	/* 	} */

	pthread_mutex_lock(&protection);
	
	pthread_mutex_lock(&acctA->mutex);
	sleep(1);
	pthread_mutex_lock(&acctB->mutex);

	pthread_mutex_unlock(&protection);

	if (acctA->balance < money) {
		pthread_mutex_unlock(&acctA->mutex);
		pthread_mutex_unlock(&acctB->mutex);
		return 0;
	}

	acctA->balance -= money;
	acctB->balance += money;

	pthread_mutex_unlock(&acctA->mutex);
	pthread_mutex_unlock(&acctB->mutex);
	return money;
}

void* start_routine1(void* arg) {
	int money = (int)arg;
	int n = transfer(&acct1, &acct2, money);
	printf("Thread 0x%lx: acct1 -> acct2($%d)\n", pthread_self(), n);
	return NULL;
}

void* start_routine2(void* arg) {
	int money = (int)arg;
	int n = transfer(&acct2, &acct1, money);
	printf("Thread 0x%lx: acct2 -> acct1($%d)\n", pthread_self(), n);
	return NULL;
}

int main(int argc, char* argv[])
{
	srand(time(NULL));
	pthread_t tid1, tid2;

	pthread_create(&tid1, NULL, start_routine1, (void*)100);
	pthread_create(&tid2, NULL, start_routine2, (void*)500);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	printf("acct1.balance: %d\n", acct1.balance);
	printf("acct2.balance: %d\n", acct2.balance);
	return 0;
}

